package com.ibm.cps.servlet;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;

import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.ibm.cps.message.MessageFields;
import com.ibm.cps.message.validation.ValidatorUtil;
import com.ibm.cps.model.AdapaterFactory;
import com.ibm.cps.model.MetadataAdapter;
import com.ibm.cps.model.PublisherMonitor;
import com.ibm.cps.model.ServletUtil;
import com.ibm.cps.test.PublishMonitor;
import com.ibm.factories.DataSourceFactory;
import com.ibm.factories.PublishProcessorFactory;
import com.ibm.interfaces.AbstractMessagePublisher;
import com.ibm.interfaces.IPersistency;
import com.ibm.mongo.MongoPersistency;
import com.ibm.util.ErrorCode;
import com.ibm.util.JSONUtility;
import com.ibm.util.exception.CPSException;

public class PublisherImplement implements ServletTemplate {

	private PublisherMonitor pmonitor;
	private IPersistency persistency;

	public PublisherImplement() throws CPSException {
		persistency = MongoPersistency.getInstace();
		pmonitor = PublisherMonitor.getInstance();
	}

	@Override
	public String doPost(Map<String, String> key2Value, String input) throws CPSException {
		String tenantid = key2Value.get(MessageFields.TENANTID);
		ValidatorUtil.checkNotNull(MessageFields.TENANTID, tenantid);
		String source = key2Value.get("source");
		if (source == null) {
			source = "rest";
		}
		return validatePublisher(tenantid, input, source);
	}

	private String validatePublisher(String tenantid, String input, String source) throws CPSException {
		if (input == null || input.length() < 1) {
			throw new CPSException(ErrorCode.INVALID_INPUT_ERROR, "Nothing to be posted.");
		}
		ArrayList<AbstractMessagePublisher> sendObjects = new ArrayList<AbstractMessagePublisher>();
		try {
			ArrayNode array = JSONUtility.getArrayFromString(input);
			ArrayNode retArray = JSONUtility.newArrayNode();

			for (int i = 0; i < array.size(); i++) {
				ObjectNode objectNode = (ObjectNode) array.get(i);
				objectNode.put(MessageFields.TYPE, MessageFields.PUBLISHER_TYPE);
				objectNode.put(MessageFields.TENANTID, tenantid);
				objectNode.put(MessageFields.SOURCE, source);
				AbstractMessagePublisher publisher = pmonitor.getFactory(tenantid).addPublishProcessor(objectNode.toString());
				ObjectNode retNode = JSONUtility.newObjectNode();
				retNode.put("id", publisher.getName());
				retArray.add(retNode);
				sendObjects.add(publisher);
			}

			for (int i = 0; i < sendObjects.size(); i++) {
				persistency.putPublisher(sendObjects.get(i).getProcessorMetadta());
			}
			return ServletUtil.constructReturnMsg(ErrorCode.SUCCESS_CODE, retArray);
		} catch (Throwable e) {
			for (int i = 0; i < sendObjects.size(); i++) {
				persistency.deletePublisher(tenantid, sendObjects.get(i).getName());
				pmonitor.getFactory(tenantid).deletePublishProcessor(sendObjects.get(i).getName(), tenantid);
			}
			throw e;
		}
	}

	@Override
	public String doGet(Map<String, String> key2Value) throws CPSException {
		String tenantid = key2Value.get(MessageFields.TENANTID);
		ValidatorUtil.checkNotNull(MessageFields.TENANTID, tenantid);
		String source = key2Value.get(MessageFields.SOURCE);
		if (source == null) {
			source = "rest";
		}
		PublishProcessorFactory publishFactory = PublisherMonitor.getInstance().getFactory(tenantid);
		DataSourceFactory factory = new DataSourceFactory();
		MetadataAdapter adapter = AdapaterFactory.getAdapter(factory, publishFactory, source);
		Collection<String> metadatas = persistency.getPublisher(tenantid, key2Value.get(MessageFields.NAME));
		Collection<String> result = adapter.getJsons(metadatas, metadatas);
		return ServletUtil.constructCollectionJson(result);
	}

	@Override
	public String doDelete(Map<String, String> key2Value) throws CPSException {
		String tenantid = key2Value.get(MessageFields.TENANTID);
		ValidatorUtil.checkNotNull(MessageFields.TENANTID, tenantid);
		String source = key2Value.get(MessageFields.SOURCE);
		if (source == null) {
			source = "rest";
		}
		Collection<String> publishers = persistency.getPublisher(tenantid, key2Value.get(MessageFields.NAME));
		Collection<String> deletedPublishers = new ArrayList<String>();
		if (publishers != null) {
			try {
				for (String pub : publishers) {
					AbstractMessagePublisher deleted = pmonitor.getFactory(tenantid)
							.deletePublishProcessor(JSONUtility.getString(MessageFields.NAME, pub), tenantid);
					persistency.deletePublisher(tenantid, deleted.getName());
					deletedPublishers.add(deleted.getProcessorMetadta());
				}
			} catch (Throwable e) {
				for (String del : deletedPublishers) {
					pmonitor.getFactory(tenantid).addPublishProcessor(del);
					persistency.putPublisher(del);
				}
				throw e;
			}
			return ServletUtil.constructReturnMsg(ErrorCode.SUCCESS_CODE,
					ServletUtil.constructCollectionJson(publishers));
		}
		return ServletUtil.constructReturnMsg(ErrorCode.SUCCESS_CODE, "Nothing to be deleted");
	}

	@Override
	public String doDelete(Map<String, String> key2Value, String input) throws CPSException {
		throw new CPSException(ErrorCode.INVALID_REQUEST_CODE, "This method is not supported now.");
	}

	@Override
	public String doPut(Map<String, String> key2Value, String input) throws CPSException {
		throw new CPSException(ErrorCode.INVALID_REQUEST_CODE, "This method is not supported now.");
	}

}
